const fs = require('fs');
const fsp = require('fs').promises;
const os = require('os');
const path = require('path');
const readline = require('readline');

function getFileLines(filePath) {
    return new Promise(resolve => {
        let count = 1;
        let inf = readline.createInterface({
            input: fs.createReadStream(filePath),
            crlfDelay: Infinity
        });
        inf.on('line', () => {
            count += 1;
        });
        inf.on('close', () => resolve(count));
    });
}

async function getPathType(filePath) {
    let stats = await fsp.stat(filePath);

    if (stats.isFile()) {
        return 'file';
    }

    if (stats.isDirectory()) {
        return 'directory';
    }

    return 'unknown';
}

async function getIgnores(folderPath) {
    let ignores = [];
    let gitignorePath = path.resolve(folderPath, '.gitignore');
    if (fs.existsSync(gitignorePath)) {
        let gitignoreContent = await fsp.readFile(gitignorePath);
        ignores = gitignoreContent.toString().split(os.EOL).filter(v => v);
        ignores.push('.gitignore');
    }
    ignores.push('.git');
    ignores = ignores.map(v => v.replace(/[\\/]$/, ''));
    return ignores;
}

/**
 * 统计指定路径下的代码行数
 *
 * @param {String} filePath 文件路径或者文件夹路径
 * @param {Object?} initObj 初始化数据，可选
 * @param {Array<String>?} ignores 忽略文件列表，必须是绝对路径
 * @returns {Promise<Object>}
 */
async function lookFolderCodeCount(filePath, initObj, ignores) {
    if (!initObj) {
        initObj = {};
    }

    let fileType = await getPathType(filePath);

    if (fileType === 'file') {
        let ext = path.extname(filePath);
        let fileLines = await getFileLines(filePath);
        initObj[ext] = (initObj[ext] || 0) + fileLines;
    } else {
        ignores = [...(ignores || []), ...await getIgnores(filePath)];
        for (const itemPath of fs.readdirSync(filePath)) {
            let targetPath = path.resolve(filePath, itemPath);
            if (!ignores.includes(path.basename(targetPath))) {
                await lookFolderCodeCount(targetPath, initObj, ignores);
            }
        }
    }

    return initObj;
}

/**
 * 打印代码行数统计，自动加载.gitignore文件过滤文件
 *
 * @param filePath 文件路径或者文件夹路径
 */
async function printFolderCodeCount(filePath = '.') {
    lookFolderCodeCount(filePath).then((result) => {
        for (let key in result) {
            console.log(`${key}语言代码：${result[key]}行`);
        }
    });
}

// 统计当前目录下文件数量
printFolderCodeCount('.');
